package org.xmeta.codes;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.xmeta.Thing;
import org.xmeta.ThingCoder;
import org.xmeta.ThingIndex;
import org.xmeta.XMetaException;

public class JsonThingCoder implements ThingCoder{
	private static final ObjectMapper mapper = new ObjectMapper();
	private static final String codeType = "xer.js";
	static{
		SimpleModule module = new SimpleModule();
		module.addDeserializer(Thing.class, new JsonDeserializer<Thing>() {
			@SuppressWarnings({ "unchecked" })
			@Override
			public Thing deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
				//先解析成Map
				Map<String, Object> valueMap = deserializationContext.readValue(jsonParser, HashMap.class);

				return createThing(valueMap);
			}

			@SuppressWarnings({ "unchecked" })
			private Thing createThing(Map<String, Object> valueMap){
				Thing thing = new Thing();
				String id = (String) valueMap.remove(XMETA_ID);

				//从Map移除子节点，这个是要放到子节点中的
				List<Map<String, Object>> children = (List<Map<String, Object>>) valueMap.remove(CHILDREN);

				//模型的属性
				thing.getAttributes().putAll(valueMap);
				//最后修改日期
				if(thing.valueExists(LAST_MODIFIED)){
					thing.getMetadata().setLastModified(thing.getLong(LAST_MODIFIED));
				}

				if(children != null && children.size() > 0){
					for(Map<String, Object> childMap : children) {
						Thing child = createThing(childMap);
						thing.addChild(child);
					}
				}

				if(id != null && !id.isEmpty()){
					thing.getMetadata().setId(id);
				}else{
					thing.getMetadata().setId(thing.getMetadata().getName());
				}
				return thing;
			}
		});

		//模型的序列化
		module.addSerializer(Thing.class, new JsonSerializer<Thing>() {
			@Override
			public void serialize(Thing thing, JsonGenerator jgen,
								  SerializerProvider pro) throws IOException {

				jgen.writeStartObject();

				try{
					//属性
					boolean descriptorsWrited = false;
					boolean extendsWrited = false;
					List<Thing> attributes = thing.getAllAttributesDescriptors();
					for(Thing attribute : attributes){
						String key = attribute.getMetadata().getName();
						if(DESCRIPTORS.equals(key)){
							descriptorsWrited = true;
						}else if(EXTENDS.equals(key)){
							extendsWrited = true;
						}
						Object value = thing.getAttribute(key);

						String defaultValue = attribute.getStringBlankAsNull("default");

						//如果没有默认值，且值为空或null，可以不保存
						if(defaultValue == null && (value == null || "".equals(value))){
							continue;
						}

						//如果默认为不为null，且值和默认值一样，可以不保存
						if(defaultValue != null && CoderUtils.isDefault(attribute, value == null ? null : value.toString())){
							continue;
						}

						if(value != null){
							jgen.writeFieldName(key);
							pro.defaultSerializeValue(value, jgen);
						}
					}

					if(!descriptorsWrited){
						String value = thing.getStringBlankAsNull(DESCRIPTORS);
						if(value != null){
							jgen.writeFieldName(DESCRIPTORS);
							pro.defaultSerializeValue(value, jgen);
						}
					}

					if(!extendsWrited){
						String value = thing.getStringBlankAsNull(EXTENDS);
						if(value != null){
							jgen.writeFieldName(EXTENDS);
							pro.defaultSerializeValue(value, jgen);
						}
					}

					//是否有特殊ID
					Object idValue = thing.getMetadata().getId();
					if(idValue != null && !idValue.equals(thing.getMetadata().getName())){
						jgen.writeFieldName(XMETA_ID);
						pro.defaultSerializeValue(idValue, jgen);
					}

					//最后修改日期
					//jgen.writeFieldName(LAST_MODIFIED);
					//pro.defaultSerializeValue(thing.getMetadata().getLastModified(), jgen);

					//子节点
					List<Thing> children = thing.getChilds();
					if(children.size() > 0) {
						jgen.writeFieldName(CHILDREN);
						pro.defaultSerializeValue(thing.getChilds(), jgen);
					}
				} finally{
					jgen.writeEndObject();
				}
			}
		});

		//模型的反序列化

		mapper.registerModule(module);
		//mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
		mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
	}

	@Override
	public void encode(Thing thing, OutputStream out) {
		try {
			mapper.writeValue(out, thing);
		}catch (Exception e){
			throw new XMetaException("Encode thing to json error", e);
		}
	}

	@Override
	public void decode(Thing thing, InputStream in, long lastModifyed) {
		try{
			Thing readThing = mapper.readValue(in, Thing.class);
			thing.getAttributes().putAll(readThing.getAttributes());
			for(Thing child : readThing.getChilds()){
				thing.addChild(child);
			}

			XmlCoder.initDefaultValues(thing);
			XmlCoder.setLastModified(thing, lastModifyed);
		}catch(Exception e){
			throw new XMetaException("decode json thing error", e);
		}
	}

	@Override
	public void decodeIndex(ThingIndex thingIndex, InputStream in, long lastModifyed) {
		try{
			Thing thing = mapper.readValue(in, Thing.class);
			
			thingIndex.name = thing.getMetadata().getName();
			thingIndex.description = thing.getString("description");
			thingIndex.descriptors = thing.getString("descriptors");
			thingIndex.extendsStr = thing.getString("extends");
			thingIndex.label = thing.getString("label");
			thingIndex.lastModified = lastModifyed;
		}catch(Exception e){
			throw new XMetaException("decode json thing error", e);
		}
	}

	@Override
	public String getType() {
		return codeType;
	}

	@Override
	public boolean acceptType(String type) {
		return codeType.equals(type);
	}

	@Override
	public String[] getCodeTypes() {
		return new String[]{codeType};
	}

}
